#include <stdio.h>
#include<stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <math.h>
#include<time.h>
#include <linux/input.h>
enum {
	b = 0x000000, //black
	r = 0xff0000, //red
	ye = 0xffff00, //yellow
	bl = 0x0000ff, //blue
	g = 0x00ff00, //green
	p = 0xff00ff, // purple
	w = 0xffffff, //white
	o = 0xFFA500 //orange
};
typedef struct node {
	int rec[480][800];
} node;
typedef struct {
	node *n;
	int top;
	int len;
} stack;

stack *createstack() {
	stack *s = (stack *)malloc(sizeof(stack));
	s->n = malloc(sizeof(node));
	s->top = 0;
	s->len = 1;
	return s;
}
void pop(stack *s, int lcdp[][800]) {
	if (s->top == s->len || s->top == 0) {
		printf("已为最初时状态 s->top:%d s->len:%d\n", s->top, s->len);
		return ;
	}
	s->top--;
	memcpy(lcdp, s->n[s->top].rec, 480 * 800 * sizeof(int));
	printf("已撤回suc\n");
}

void push(stack *s, int lcdp[][800]) {

	if (s->top == s->len - 1) {
		s->n = realloc(s->n, sizeof(node) * (s->len *= 2));

	} else if (s->n == NULL) {
		printf("扩容fail\n");
		exit(-1);
	}
	memcpy(s->n[s->top].rec, lcdp, 480 * 800 * sizeof(int));
	s->top++;
	printf("已记录suc; s->len:%d,s->top:%d\n", s->len, s->top);
}

void perfor(int lcdp[][800]) {
	int i, j;
	int color[6] = {b, r, p, ye, bl, g};
	for (i = 0; i < 480; i++) {
		for (j = 0; j < 800; j++) {
			if (j == 750)
				lcdp[i][j] = b;
			else lcdp[i][j] = w;
		}
	}
//圆心1 r=4|8
	int rx = 775, ry = 25;

	for ( i = 0; i < 480; i++)
		for (j = 750; j < 800; j++) {
			if ((j - rx) * (j - rx) + (i - ry) * (i - ry) <= 16)
				lcdp[i][j] = 0;
		}
//尺寸滑块条
	for ( i = 25; i < 125; i++)
		lcdp[i][775] = 0;
//圆心3
	ry = 125;
	for ( i = 0; i < 480; i++)
		for (j = 750; j < 800; j++) {
			if ((j - rx) * (j - rx) + (i - ry) * (i - ry) <= 64)
				lcdp[i][j] = 0;
		}
//颜色选择滑块条
	ry = 160; //y:160-310
	int  count = 0, choose = 0;
	for (i = 160; i < 310; i ++) {
		if (count == 25) {
			choose = (++choose) % 6;
			count = 0;
		} else count++;
		for (j = 760; j < 790; j++) {
			lcdp[i][j] = color[choose];

		}
	}
	//橡皮擦区域
	for (i = 320; i < 480; i++)
		for (j = 760; j < 790; j++) {
			if (i >= 320 && i <= 380)
				lcdp[i][j] = b;
			else if (i > 380 && i < 440)
				lcdp[i][j] = o;
			else lcdp[i][j] = r;
		}
}
int draw(int cho, int lcdp[][800], int x, int y, int color) {
	for (int i = 0; i < 480; i++) {
		for (int j = 0; j < 750; j++)
			if ((j - x) * (j - x) + (i - y) * (i - y) <= cho) {
				lcdp[i][j] = color;
			}
	}
}
void rubber(int cho, int lcdp[][800], int x, int y) {
	for (int i = 0; i < 480; i++) {
		for (int j = 0; j < 750; j++)
			if ((j - x) * (j - x) + (i - y) * (i - y) <= cho) {
				lcdp[i][j] = w;
			}
	}
}
int pos(int lcdp[][800], stack *s, int *cho, int *x, int *fx, int *y, int *fy, int *color, int *flag) {
	int i, j;
	int lcdt = open("/dev/input/event0", O_RDWR);
	if (lcdt < 0) {
		perror("input error\n");
		return -1;
	}
	struct input_event touch;
	static time_t start, end;
	while (1) {
		int read_ret = read(lcdt, &touch, sizeof(struct input_event));
		if (read_ret < 0) {
			perror("read touch failed\n");
			return -1;
		}

		if (touch.type == EV_ABS) {
			if (touch.code == ABS_X)
				*x = touch.value * 800 / 1024;
			else if (touch.code == ABS_Y) {
				*y = touch.value * 480 / 600;
			}
		}

		printf("cho=%d,fy=%d y=%d fx=%d x=%d\n", *cho, *fy, *y, *fx, *x);
		if (touch.type == EV_KEY) {
			if (*x > 750 && *x < 800 && *y >= 320 && *y < 380) {
				if (touch.code == BTN_TOUCH && touch.value == 1) {
					time(&start);
					printf("start\n");
				} else if (touch.code == BTN_TOUCH && touch.value == 0) {
					time(&end);
					printf("end\n");
					double times = difftime(end, start);
					if (times < 1)
						*flag = 0;
					else if (times >= 1)
						pop(s, lcdp);
				}

			} else if ((*x > 0 && *x <= 750) && (*y > 0 && *y < 480))  {
				if (touch.code == BTN_TOUCH && touch.value == 1) {
					printf("记录中\n");
					push(s, lcdp);
				}
			} else if ((*x > 750 && *x <= 800) && (*y > 380 && *y < 440)) {
				if (touch.code = BTN_TOUCH && touch.value == 1) {
					srand(time(NULL));
					int sel = rand() % 8;
					int color[8] = {b, r, w, ye, bl, p, o, g};
					int tim = rand() % 100;
					int dir = rand() % 5;
					int path = rand() % 6;
					for (i = 0; i < tim; i++) {
						*x = rand() % 300;
						*y = rand() % 300;
						printf("x:%d y:%d", *x, *y);
						switch (dir) {
							case 0:
								lcdp[*x + path][*y + path] = color[sel];
								break;
							case 1:
								lcdp[*x + path][*y - path] = color[sel];
								break;
							case 2:
								lcdp[*x - path][*y + path] = color[sel];
								break;
							case 3:
								lcdp[*x - path][*y - path] = color[sel];
								break;
						}
					}
				}
			}
		}
		if (touch.type == EV_SYN) {
			if (*flag == 1) {
				draw(*cho, lcdp, *x, *y, *color);
			} else {
				rubber(*cho, lcdp, *x, *y);
			}

			if (*x > 750 && *x < 800) {
				if (*y > 440 && *y <= 480)
					perfor(lcdp);
				else if (*y >= 160 && *y <= 310) {
					*flag = 1;
					if (*y > 160 && *y < 185)
						*color = b;
					else if (*y >= 185 && *y < 210)
						*color = r;
					else if (*y >= 210 && *y < 235)
						*color = p;
					else if (*y >= 235 && *y < 260)
						*color = ye;
					else if (*y >= 260 && *y < 285)
						*color = bl;
					else if (*y >= 285 && *y < 310)
						*color = g;
				} else if (*y >= 30 && *y <= 110 ) {
					for (j = 760; j < 790; j++) {
						lcdp[*fy][j] = w;
						if (j == 775)
							lcdp[*fy][j] = b;
					}
					*fx = *x;
					*fy = *y;
					*cho = *fy;
					for (j = 760; j < 790; j++)
						lcdp[*fy][j] = r;
				}
			}
		}

	}
	close(lcdt);
}

int main() {
	int lcd = open("/dev/fb0", O_RDWR);
	int (*lcdp)[800] = (int (*)[800])mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, lcd, 0);
	int  cho = 30, x = 0, fx = 0, y = 0, fy = 30, color = b, flag = 1, i, j;

	//初始化白板
	perfor(lcdp);
	//小画笔范围 （x:750-800,y:0-50） 中画笔y:120-180 大画笔y:220-280 橡皮y:350-480
	//初始化栈
	stack *s = createstack();

	while (1) {
		cho = pos(lcdp, s, &cho, &x, &fx, &y, &fy, &color, &flag);

	}
	if (s->n)
		free(s->n);
	if (s)
		free(s);
	close(lcd);
	return 0;

}
